<?php
require_once 'utils.php';
class User {
    public $login;
    public $pwd;
    public $sn; //surname
    public $gn; //given name
    public $bd; //birthday
    public $email;

    public function __construct($arg = array()){ //Constructor considerates the list of properites of User and fill it with an array.
        $rfc = new ReflectionClass('User');
        $rfp = $rfc->getProperties();
        $fillLength = min(sizeof($rfp),sizeof($arg));
        for ($i=0;$i<$fillLength;$i++) $rfp[$i]->setValue($this,$arg[$i]);
    }

    public function fillWithPost() {
        $rfc = new ReflectionClass('User');
        $rfp = $rfc->getProperties();
        foreach ($rfp as $property) {
            $name = $property->getName();
            if (isset($_POST[$name])) $property->setValue($this,$_POST[$name]);
        }
    }

    public static function getUser($login) {
        $dbh = Database::connect();
        $query = "SELECT * FROM `user` WHERE `login` = ?";
        $sth = $dbh->prepare($query);
        $sth->execute(array($login));
        $sth->setFetchMode(PDO::FETCH_CLASS, 'User');
        $user = $sth->fetch(PDO::FETCH_CLASS);
        if ($sth) return $user; else return null;
    }

    public static function checkUser($login,$pwd) {
        $dbh = Database::connect();
        $query = "SELECT * FROM `user` WHERE `login` = ? AND `pwd` = SHA1(?)";
        $sth = $dbh->prepare($query);
        $sth->execute(array($login,$pwd));
        return $sth->rowCount()==0 ? false : true;
    }

    public static function insertUser($user) {
        $dbh = Database::connect();
        $parray = (array)$user;
        $keyString = "";
        $valueString ="";
        $first = true;
        foreach ($parray as $key => $value) {
            $keyString .= ($first?"":", ")."`".$key."`";
            $valueString .= ($first?"":", ").($key=="pwd"?"SHA1(?)":"?");
            $first = false;
        }
        $query = "INSERT INTO `user` (".$keyString.") VALUES(".$valueString.")";
        $sth = $dbh->prepare($query);
        $sth->execute(array_values($parray));
    }

}

class ManageUser {
 /* This methode writes right information in to $_SESSION["login"].
 *
 * Once required, this package does:
 *     1. check whether $_GET["login"], $_POST["login"] and $_POST["pwd"] exist or not.
 *     1.1. If so, compare them to the database.
 *     1.1.1. if correct, overwrite "login" into $_SESSION. check whether
 *            $_SESSION["kpcookie"] exists and is equal to "checked" or not.
 *     1.1.1.1 if so, setcookie "login" to login.
 *     1.1.1.2 if not, do nothing.
 *     1.1.2. if not, do nothing.
 *     1.2. if not, do nothing.
 *     2. check $_SEESION["login"].
 *     2.1 if empty, check cookies.
 *     2.1.1 if cookies "login" exists and is valid, write it to $_SESSION["login"].
 *     2.1.2 if not write "anonyme" into $_SESSION["login"].
 *     2.2 if not, do nothing.
 *
 * - call this medthod before responsing the client to ensure that every php
 *   page can get useful information in $_SESSION["login"].
 */

    public static function doLogin() {
        $m = new Messages();
        if (Client::hasCommand("login") && isset($_POST["login"]) && isset($_POST["pwd"])) {
            $login = $_POST["login"];
            $pwd = $_POST["pwd"];
            if (User::checkUser($login, $pwd)) {
                $_SESSION["login"] = $login;
                $m=new Messages('', 501); //need refresh
                if (isset($_POST["kpcookie"]) && $_POST["kpcookie"] == "checked")
                    setcookie("login",$login);
            } else {
                return new Messages('wrong username or password', 301);
            }
        }

        if (!isset($_SESSION["login"])) {
            $_SESSION["login"] = (isset($_COOKIE["login"]) &&
                    User::getUser($_COOKIE["login"])) ? $_COOKIE["login"] : "anonyme";
        }
        return $m;
    }

 /* This function creat user enter in database.
 *
 * Once required, this package does:
 *     1. check whether $_GET["signup"] or $_GET["checksignup"] exists or not.
 *     1.1 if so, check every information needed.
 *     1.1.1 if all pass,
 *     1.1.2 when encounter exception, throw it.
 *     1.2 if not, do nothing.
 */

    public static function doSignup() {
        $m = new Messages();
        if (Client::hasCommand("signup")) {
            $m = ManageUser::checkSignup();
            if (!$m->hasMessage()) {
                $user = new User();
                $user->fillWithPost();
                User::insertUser($user);
                $_SESSION["login"]=$user->login;
                return new Messages('', 501); //need refresh
            } else {
                return $m;
            }
        }
        return $m;
    }

    /* This package writes right information in to $_SESSION["login"] and redirect to index.php
 *
 * Once required, this package does:
 *     1. check whether $_GET["logout"] exist or not.
 *     1.1. If so, unset cookie "login" and write "anonyme" into $_SESSION["login"].
 *     1.2 If not, do nothing.
 *
 * - Require this package before responsing the client and after checkLogin.php
 *   to ensure that every php page can get useful information in
 *   $_SESSION["login"].
 */

    public static function doLogout() {
        $m = new Messages();
        if (Client::hasCommand("logout")) {
            setcookie("login");
            $_SESSION["login"] = "anonyme";
            return new Messages('refresh:0', 501); //need refresh
        }
        return $m;
    }

    public static function checkSignup() {
        $m = new Messages();
        if (!isset($_POST["login"])) {
            $m->pushMessage("login cannot be null",401);
        } else {
            $login = $_POST["login"];
            if (strlen($login)==0) $m->pushMessage("login cannot be null",401);
            if (strlen($login)>64) $m->pushMessage("login is too long",402);
            if (preg_replace("/[\da-zA-Z_\.]+/", "", $login)<>"")
                $m->pushMessage("login can only contain letters, numbers, underline and dot.",403);
            if (User::getUser($_POST["login"]))
                $m->pushMessage("login name already existed",404);
        }
        if (!isset ($_POST["pwd"])) {
            $m->pushMessage("password cannot be null",405);
        } else {
            $pwd = $_POST["pwd"];
            if (strlen($pwd)<6) $m->pushMessage("password too short",406);
            if (strlen($pwd)>40) $m->pushMessage("password too long",407);
        }
        if (!(isset($_POST["sn"]) && strlen($_POST["sn"])>0))
            $m->pushMessage("Surname cannot be null",408);
        if (isset($_POST["sn"]) && strlen($_POST["sn"])>64)
            $m->pushMessage("Surname too long",409);
        if (!(isset($_POST["gn"]) && strlen($_POST["gn"])>0))
            $m->pushMessage("Given name cannot be null",410);
        if (isset($_POST["gn"]) && strlen($_POST["gn"])>64)
            $m->pushMessage("Given name too long",411);
        if (!(isset($_POST["bd"]) && strtotime($_POST["bd"])))
            $m->pushMessage("Birthday format invalid",412);
        if (!isset ($_POST["email"])) {
            $m->pushMessage("email cannot be null",413);
        } else {
            $email = $_POST["email"];
            if (strlen($email)==0) $m->pushMessage("email cannot be null",413);
            if (strlen($email)>128) $m->pushMessage("email is too long",414);
            if (preg_replace("/ *[\da-zA-Z\-_\.]+@([\da-zA-Z]+\.)+[a-zA-Z]+ */", "", $email)<>"") $m->pushMessage("Email address format invalid",415);
        }
        require_once 'dapphp/securimage.php';
        $image = new Securimage();
        if (!(isset($_POST['code'])&&$image->check($_POST['code']))) {
            $m->pushMessage("Captcha wrong!",416);
        }

        return $m;
    }

}
?>
